package com.lk;

import org.junit.Test;

import java.time.Duration;
import java.time.Instant;
import java.util.OptionalLong;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;

/**
 * forkjoinpool将同一个时间交由多个线程处理
 * 根据临界点拆分成不同的线程
 * 最后合并结果
 *
 * 拆分线程会出现性能消耗，当使用forkjoinpool的效率没有线性执行高时：
 * 1.处理的数据太小
 * 2.临界点太小，拆分的线程太多
 *
 */
public class TestForkJoinPool {
    public static void main(String[] args) {//379
        Instant start = Instant.now();

        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoinSumCalculate(0L,1000000000L);
        Long sum = pool.invoke(task);
        System.out.println(sum);

        Instant end = Instant.now();
        System.out.println("消耗时间："+ Duration.between(start,end).toMillis());
    }

    @Test
    public void test1(){//400
        Instant startTime = Instant.now();

        long start = 0 ;
        long end = 1000000000L;
        long sum= 0;
        for(long i=start;i<=end;i++){
            sum+=i;
        }
        System.out.println(sum);

        Instant endTime = Instant.now();
        System.out.println("消耗时间："+ Duration.between(startTime,endTime).toMillis());
    }

    @Test
    public void test2(){
        Instant startTime = Instant.now();

        OptionalLong sum = LongStream.rangeClosed(0L,1000000000L)
                    .parallel()
                    .reduce(Long::sum);
        System.out.println(sum);

        Instant endTime = Instant.now();
        System.out.println("消耗时间："+ Duration.between(startTime,endTime).toMillis());
    }
}

class ForkJoinSumCalculate extends RecursiveTask<Long> {

    private long start;
    private long end;
    //临界值
    private final static long THURSHOLD= 100000L;

    public ForkJoinSumCalculate(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        long length = end-start;
        if(length<THURSHOLD){
            long sum=0L;
            for(long i=start;i<=end;i++){
                sum+=i;
            }
            return sum;
        }else{
            long mix = (start+end)/2;
            ForkJoinSumCalculate left = new ForkJoinSumCalculate(start,mix);
            left.fork();//拆分，同时压入线程队列
            ForkJoinSumCalculate right = new ForkJoinSumCalculate(mix+1,end);
            right.fork();//拆分，同时压入线程队列
            //合并
            return left.join()+right.join();
        }
    }
}